/* 
  Copyright (c) SilverLining 2015
  Date:    2016-1-7
  File:    pool_cleaner.cpp  
  Description: 

*/

#include "stdafx.h"


using namespace m::alloc;
using namespace m::error;

#define REPORT_INTERVAL 10

// Define cleanup intervals proportional to the amount of commit charge used. More commit charge = quicker intervals.
#define MIN_INTERVAL .1
#define MAX_INTERVAL 10.
#define DEFAULT_INTERVAL 1.

#define TAG_POOLCLEANER L"pool_cleaner: "

namespace m
{
	namespace alloc
	{
		pool_cleaner::pool_cleaner()
			: _PoolTimer(nullptr),
			_Cycle(0)
		{

		}

		pool_cleaner::~pool_cleaner()
		{
			clear(_PoolTimer);
		}

		void pool_cleaner::process_entry()
		{
			DBGL(TAG_POOLCLEANER L"Starting pool cleaner.");
			int i = 0;
			size_t Cleaned = 0;

			this->set_one_shot_timer(&_PoolTimer, DEFAULT_INTERVAL, L"us.sl.m.poolClean");

			while (started())
			{
				while (next_message());
			}

			DBGL(TAG_POOLCLEANER L"Stopping pool cleaner.");
		}

		bool pool_cleaner::handle_message(message* m)
		{
			ref_storage track1;
			process* sender = lock<process>(track1, m->sender());

			if (sender == this && m->type_equals(L"us.sl.m.poolClean"))
			{
				size_t unused = pool.UnusedPoolSize;
				size_t used = pool.UsedPoolSize;

				_Cleaned += pool.clear(unused);
				++_Cleaned;

				if (_Cycle % 10 == 0)
				{
					DBGL(TAG_POOLCLEANER L"Cleaned %dbytes so far.", _Cleaned);
				}
				++_Cycle;

				// Calculate pool usage as a ratio of used pool to unused.
				scalar interval = DEFAULT_INTERVAL;
				if (unused > 0)
				{
					scalar poolFree = 1. - ((scalar)used / (scalar)(used + unused));
					interval = MIN_INTERVAL + (MAX_INTERVAL - MIN_INTERVAL) * poolFree * poolFree;
					if (interval > MAX_INTERVAL)
					{
						interval = MAX_INTERVAL;
					}
					else if (interval < MIN_INTERVAL)
					{
						interval = MIN_INTERVAL;
					}
				}

				this->set_one_shot_timer(&_PoolTimer, interval, L"us.sl.m.poolClean");

				return true;
			}
			return false;
		}
	}
}